Skip to content

feat!: rewrite to the current Mnemo API contract (0.2.0) - #2

Merged
shhahhussain merged 2 commits into
mainfrom
fix/api-contract-0.2
Oct 15, 2026
Merged

shhahhussain merged 2 commits into
mainfrom
fix/api-contract-0.2

Conversation

@shhahhussain

Copy link
Copy Markdown
Contributor

What

Rewrites the Python SDK to the live API contract, mirroring the TS getmnemo 0.6 surface in Pythonic form. Breaking release: 0.1.2 → 0.2.0.

Why

The published 0.1.2 is incompatible with the API — every call fails:

  • POST /v1/memories sent {content}; the API wants {containerTag|scope, items:[{content, metadata?}]} and the global ValidationPipe 400s unknown keys
  • POST /v1/search sent {query}; the API wants {q, containerTag, limit?} and returns {results: [...]}, not hits
  • workspace_id was required and models expected workspaceId/actorId, which no longer exist (identity comes from the API key)

Changes

  • Mnemo(api_key, *, default_container_tag=None, workspace_id=None (deprecated, header only when given), base_url=None, ...); env fallbacks GETMNEMO_API_KEY / GETMNEMO_CONTAINER_TAG / GETMNEMO_WORKSPACE_ID
  • add(content, *, container_tag=None, metadata=None) → AddResponse (items/stats/receipt); new add_many(items, *, container_tag=None) for 1–100 items with client-side unknown-key rejection
  • search(q, *, container_tag=None, limit=None) → list[SearchHit] typed from the real SearchResultDto fields; 404 "Container not found" → [] (and tolerates the in-flight empty-array change)
  • Missing container raises a clear error naming the "<type>:<id>" format
  • actor_id dropped everywhere; update/delete/list thread the container as query params
  • Canonical import is now getmnemo (matches the install name, the LangChain adapter, and the docs); mnemo stays as a back-compat alias module — note the published 0.1.2 wheel only shipped mnemo, so from getmnemo import ... was broken until now
  • Retry/timeout behaviour unchanged; sync + async clients kept in lockstep
  • README quickstart rewritten (add → search → results) + 0.1.x migration notes

Test plan

  • pytest — 16 passed (Python 3.9.6, the floor of requires-python)
  • ruff check src tests — clean
  • mypy src (strict) — clean
  • Request-body regression tests assert bodies contain ONLY API-accepted keys (add, add_many, search)
  • 404→[] covered sync + async; future 200+empty-results shape covered
  • Live smoke against api.mnemohq.com with a real key (not run here)

Deferred

  • scope object form ({type, id, tags}) — containerTag covers the SDK surface for now
  • Trusted Publishing for PyPI (publish.yml still uses secrets.PYPI_TOKEN via twine on tag v*; left untouched)

Do not merge/tag/publish — release prep only.

The published 0.1.2 predates the container-scoped API and every request it
sends is rejected: POST /v1/memories got {content} instead of
{containerTag, items:[...]}, POST /v1/search got {query} instead of {q},
and responses were parsed as hits/workspaceId which no longer exist.

- Containers are now first-class: default_container_tag on the client
  (env GETMNEMO_CONTAINER_TAG) or container_tag per call, format <type>:<id>
- add() posts {containerTag, items:[{content, metadata?}]} and returns the
  typed AddResponse (items, stats, receipt); new add_many() for 1-100 items
- search() posts {q, containerTag, limit?} and returns list[SearchHit]
  with the real response fields (resultType, score, scopeKey, polarity, ...)
- search() treats 404 'Container not found' as empty results and tolerates
  the upcoming empty-array response shape
- workspace_id is deprecated-optional: identity comes from the API key;
  the x-workspace-id header is only sent when explicitly configured
- actor_id removed everywhere (no longer part of the API)
- update/delete/list thread the container as query params
- canonical import is now 'getmnemo' (matches the install name and the
  LangChain adapter); 'mnemo' remains as a back-compat alias module
- tests pin the wire shapes: bodies carry ONLY API-accepted keys
  (unknown-key regression), 404->[] on search, env fallbacks, both clients
…n retried writes

- search (sync + async) returns [] only when a 404 body message says
  'Container not found'; any other 404 raises MnemoHTTPError
- add/add_many generate a per-item uuid4 idempotencyKey when the caller gave
  none and retries are enabled; the payload is built once, so every retry
  carries the same key (no duplicate writes on 5xx/429/transport retries)
@shhahhussain
shhahhussain merged commit 498fcab into main Oct 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant